#include "flow_service.h"
#include "context.h"
#include "streamdata.h"
#include "log.h"
#include "util.h"
#include "apiordercache.h"
#include "1000_flow.pb.h"
#include "9200_agency_event_api.pb.h"


void FlowService::OnMatchReg(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
    std::uint32_t matchid, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t fee, std::uint32_t matchtype, std::int64_t matchtime)
{
    switch (result)
    {
        case agency_event_api::ErrorCode::Success:
        case agency_event_api::ErrorCode::RespTimeout:
            RecordMatchReg(result, uid, provider, agencyid, gameid, matchid, orderid, optime, balance, fee, matchtype, matchtime);
            break;
        default:
        {
            if (ApiOrderCache::Instance()->CheckCancelMatchReg(orderid))
            {
                // 报名失败 + 有撤销记录, 则 增加流水上报
                RecordMatchReg(result, uid, provider, agencyid, gameid, matchid, orderid, optime, balance, fee, matchtype, matchtime);
                //清理缓存
                // log_debug("ClearCancelMatchReg, uid:%u,gameid:%u,matchid:%llu,orderid:%llu", uid, gameid, matchid, orderid);
                ApiOrderCache::Instance()->ClearCancelMatchReg(orderid);
            }
            else 
            {
                // 缓存 下注记录
                ApiOrderCache::Data op_data; 
                op_data.result              = result               ;
                op_data.uid                 = uid                  ;
                op_data.provider            = provider             ;
                op_data.agencyid            = agencyid             ;
                op_data.gameid              = gameid               ;
                op_data.cycle               = matchid              ;
                op_data.orderid             = orderid              ;
                op_data.optime              = optime               ;
                op_data.balance             = balance              ;
                op_data.fee                 = fee                  ;
                op_data.matchtype           = matchtype            ;
                op_data.matchtime           = matchtime            ;
                op_data.expire_time         = CTools::GetUnixTime() + 60;
                // log_debug("CacheBetFailed, uid:%u,gameid:%u,matchid:%llu,orderid:%llu", uid, gameid, matchid, orderid);
                ApiOrderCache::Instance()->CacheMatchRegFailed(orderid, std::move(op_data));
            }
            return;
        }
    }
}

void FlowService::OnCancleMatchReg(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
    std::uint64_t matchid, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t fee, std::int64_t matchtime, std::uint32_t matchtype, std::uint64_t associatedorder)
{
    ApiOrderCache::Data* op_data = ApiOrderCache::Instance()->CheckMatchRegFailed(associatedorder); 
    if (op_data != nullptr)
    {
        // 记录 报名失败
        RecordMatchReg(op_data->result, op_data->uid, op_data->provider, op_data->agencyid, op_data->gameid, op_data->cycle, 
            op_data->orderid, op_data->optime, op_data->balance, op_data->fee, op_data->matchtype, op_data->matchtime);
        // 记录 取消操作
        RecordCancleMatchReg(result, uid, provider, agencyid, gameid, 
            matchid, orderid, optime, balance, fee, matchtime, matchtype, associatedorder);
        //清理缓存
        // log_debug("ClearBetFailed, uid:%u,gameid:%u,matchid:%llu,orderid:%llu", op_data->uid, op_data->gameid, op_data->matchid, op_data->orderid);
        ApiOrderCache::Instance()->ClearMatchRegFailed(associatedorder);
    }
    else
    {
        // 缓存 取消记录
        // log_debug("CacheCancleBet, uid:%u,gameid:%u,matchid:%llu,orderid:%llu,associatedorder:%llu", uid, gameid, matchid, orderid, associatedorder);
        ApiOrderCache::Instance()->CacheCancelMatchReg(associatedorder, CTools::GetUnixTime() + 60);

        // 记录 取消操作
        RecordCancleMatchReg(result, uid, provider, agencyid, gameid, 
            matchid, orderid, optime, balance, fee, matchtime, matchtype, associatedorder);
    }
}

void FlowService::OnMatchSettlement(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, std::int64_t withdraw_limit, std::int64_t valid_flow,
    std::uint64_t matchid, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t fee, std::int64_t matchtime, std::uint32_t matchtype, std::int64_t reward,
    std::int64_t withdraw_limit_ratio)
{
    RecordMatchSettlement(result, uid, provider, agencyid, gameid, withdraw_limit, valid_flow,
        matchid, orderid, optime, balance, fee, matchtime, matchtype, reward,
        withdraw_limit_ratio);
}

void FlowService::OnMatchReward(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, std::int64_t withdraw_limit,
    std::uint64_t matchid, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t fee, std::int64_t matchtime, std::uint32_t matchtype, std::int64_t reward, std::int64_t reward_id,
    std::int64_t withdraw_limit_ratio, std::int32_t reward_type, std::int64_t reward_sum_limit, std::int32_t reward_cash)
{
    RecordMatchReward(result, uid, provider, agencyid, gameid, withdraw_limit,
        matchid, orderid, optime, balance, fee, matchtime, matchtype, reward, reward_id,
        withdraw_limit_ratio, reward_type, reward_sum_limit, reward_cash);
}

void FlowService::RecordMatchReg(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
    std::uint32_t matchid, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t fee, std::uint32_t matchtype, std::int64_t matchtime)
{
    if (fee > 0)
    {
        flow::FlowPush flow_push;
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_MATCH_REG);
        flow->mutable_op()->set_delt(-fee);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(matchid);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->set_optime(optime);
        flow->set_balance(balance);

        
        Json::Value ext_data;
        ext_data["matchtype"] = matchtype;
        ext_data["matchtime"] = Json::Int64(matchtime);
        ext_data["fee"] = Json::Int64(fee);
        std::string ext_string = CTools::ToStr(ext_data);
        flow->set_ext(ext_string);

        log_debug("flow_push:%s", flow_push.ShortDebugString().c_str());
        Ctx.host->MtSendtoSrv(flow::FLOW_CMD_FLOW_PUSH, SERVER_TYPE_FLOW, &flow_push, uid);
    }
    else
    {
        log_error("flow_push: orderid=%ld, uid=%d, agencyid=%d, gameid=%d, fee=%ld", orderid, uid, agencyid, gameid, fee);
    }
    
}

void FlowService::RecordCancleMatchReg(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, 
    std::uint64_t matchid, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t fee, std::int64_t matchtime, std::uint32_t matchtype, std::uint64_t associatedorder)
{
    if (fee > 0)
    {
        flow::FlowPush flow_push;
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_MATCH_UNREG);
        flow->mutable_op()->set_delt(fee);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(matchid);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->mutable_gameinfo()->set_associatedorder(associatedorder);
        flow->set_optime(optime);
        flow->set_balance(balance);

        Json::Value ext_data;
        ext_data["matchtype"] = matchtype;
        ext_data["matchtime"] = Json::Int64(matchtime);
        ext_data["fee"] = Json::Int64(fee);
        std::string ext_string = CTools::ToStr(ext_data);
        flow->set_ext(ext_string);

        log_debug("flow_push:%s", flow_push.ShortDebugString().c_str());
        Ctx.host->MtSendtoSrv(flow::FLOW_CMD_FLOW_PUSH, SERVER_TYPE_FLOW, &flow_push, uid);
    }
    else
    {
        log_error("flow_push: orderid=%ld, uid=%d, agencyid=%d, gameid=%d, fee=%ld", orderid, uid, agencyid, gameid, fee);
    }
}

void FlowService::RecordMatchSettlement(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, std::int64_t withdraw_limit, std::int64_t valid_flow,
    std::uint64_t matchid, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t fee, std::int64_t matchtime, std::uint32_t matchtype, std::int64_t reward,
    std::int64_t withdraw_limit_ratio)
{
    if (reward > 0)
    {
        flow::FlowPush flow_push;
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_MATCH_SETTLEMENT);
        flow->mutable_op()->set_delt(reward);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(matchid);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->set_optime(optime);
        flow->set_balance(balance);

        Json::Value ext_data;
        ext_data["matchtype"] = matchtype;
        ext_data["matchtime"] = Json::Int64(matchtime);
        ext_data["fee"] = Json::Int64(fee);
        ext_data["reward"] = Json::Int64(reward);
        ext_data["withdraw_limit"] = Json::Int64(withdraw_limit);
        ext_data["valid_flow"] = Json::Int64(valid_flow);
        // ext_data["withdraw_limit_ratio"] = Json::Int64(withdraw_limit_ratio);
        
        std::string ext_string = CTools::ToStr(ext_data);
    
        flow->set_ext(ext_string);

        log_debug("flow_push:%s", flow_push.ShortDebugString().c_str());
        Ctx.host->MtSendtoSrv(flow::FLOW_CMD_FLOW_PUSH, SERVER_TYPE_FLOW, &flow_push, uid);
    }
    else
    {
        log_error("flow_push: orderid=%ld, uid=%d, agencyid=%d, gameid=%d, fee=%ld", orderid, uid, agencyid, gameid, fee);
    }
}

void FlowService::RecordMatchReward(std::int32_t result, std::uint32_t uid, const std::string& provider, std::uint32_t agencyid, std::uint32_t gameid, std::int64_t withdraw_limit,
    std::uint64_t matchid, std::uint64_t orderid, std::uint64_t optime, std::int64_t balance, std::int64_t fee, std::int64_t matchtime, std::uint32_t matchtype, std::int64_t reward, std::int64_t reward_id,
    std::int64_t withdraw_limit_ratio, std::int32_t reward_type, std::int64_t reward_sum_limit, std::int32_t reward_cash)
{
    if (reward > 0)
    {
        flow::FlowPush flow_push;
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(uid);
        flow->mutable_op()->set_act(flow::ACT_MATCH_REWARD);
        flow->mutable_op()->set_delt(reward);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agencyid);
        flow->mutable_gameinfo()->set_gameid(gameid);
        flow->mutable_gameinfo()->set_cycle(matchid);
        flow->mutable_gameinfo()->set_orderid(orderid);
        flow->set_optime(optime);
        flow->set_balance(balance);

        Json::Value ext_data;
        // ext_data["matchtype"] = matchtype;
        // ext_data["matchtime"] = Json::Int64(matchtime);
        // ext_data["fee"] = Json::Int64(fee);
        ext_data["reward"] = Json::Int64(reward);
        ext_data["rewardid"] = Json::Int64(reward_id);
        ext_data["rewardcash"] = reward_cash;
        ext_data["rewardtype"] = reward_type;
        // ext_data["withdraw_limit"] = Json::Int64(withdraw_limit);
        // ext_data["withdraw_limit_ratio"] = Json::Int64(withdraw_limit_ratio);
        // ext_data["reward_type"] = reward_type;
        // ext_data["reward_sum_limit"] = Json::Int64(reward_sum_limit);
        
        std::string ext_string = CTools::ToStr(ext_data);
        flow->set_ext(ext_string);

        log_debug("flow_push:%s", flow_push.ShortDebugString().c_str());
        Ctx.host->MtSendtoSrv(flow::FLOW_CMD_FLOW_PUSH, SERVER_TYPE_FLOW, &flow_push, uid);
    }
    else
    {
        log_error("flow_push: orderid=%ld, uid=%d, agencyid=%d, gameid=%d, fee=%ld", orderid, uid, agencyid, gameid, fee);
    }
}


void FlowService::OnPurchaseReg(std::int32_t result, std::int64_t balance, const std::string &provider, std::uint32_t user_id, 
    std::uint32_t agency_id, std::uint32_t game_id, std::uint64_t cycle, std::uint64_t order_id, std::uint64_t optime, std::int64_t fee, std::int64_t purchase_time)   
{
    // 根据返回错误码判断
    // 扣款失败 无效扣款     +  (if有撤单记录->上报flow) 
    // 扣款成功 有效扣款     +  上报flow
    // 扣款超时 未知扣款状态 +  上报flow

    switch (result)
    {
        case agency_event_api::ErrorCode::Success:
        case agency_event_api::ErrorCode::RespTimeout:
            RecordPurchaseReg(result, balance, provider, user_id, agency_id, game_id, cycle, order_id, optime, fee, purchase_time);
            break;
        default:
        {
            if (ApiOrderCache::Instance()->CheckCancelMatchReg(order_id))
            {
                // 扣款失败 + 有撤销记录, 则 增加流水上报
                RecordPurchaseReg(result, balance, provider, user_id, agency_id, game_id, cycle, order_id, optime, fee, purchase_time);
                //清理缓存
                ApiOrderCache::Instance()->ClearCancelMatchReg(order_id);
            }
            else 
            {
                // 缓存 下注记录
                ApiOrderCache::Data op_data; 
                op_data.result              = result               ;
                op_data.balance             = balance              ;
                op_data.provider            = provider             ;
                op_data.uid                 = user_id              ;
                op_data.agencyid            = agency_id            ;
                op_data.gameid              = game_id              ;
                op_data.cycle               = cycle                ;
                op_data.orderid             = order_id             ;
                op_data.optime              = optime               ;
                op_data.fee                 = fee                  ;
                op_data.purchase_time       = purchase_time        ;
                op_data.expire_time         = CTools::GetUnixTime() + 60;
                // log_debug("CacheBetFailed, uid:%u,gameid:%u,matchid:%llu,orderid:%llu", uid, gameid, matchid, orderid);
                ApiOrderCache::Instance()->CacheMatchRegFailed(order_id, std::move(op_data));
            }
            return;
        }
    }
}
void FlowService::OnCancelPurchaseReg(std::int32_t result, std::int64_t balance, const std::string &provider, std::uint32_t user_id, 
    std::uint32_t agency_id, std::uint32_t game_id, std::uint64_t cycle, std::uint64_t optime, std::int64_t fee, std::int64_t purchase_time, std::uint64_t order_id, std::uint64_t cancel_purchase_orderid) 
{
    // 根据返回码判断
    // 撤单成功 同步资产     + 撤单上报flow+(if有购买失败记录->购买上报flow)
    // 撤单超时 记录异常日志 + 撤单上报flow+(if有购买失败记录->购买上报flow)
    // 撤单失败 同步资产     单上报flow
    
    ApiOrderCache::Data* op_data = ApiOrderCache::Instance()->CheckMatchRegFailed(cancel_purchase_orderid); 
    if (op_data != nullptr)
    {
        //  购买失败
        RecordPurchaseReg(
            op_data->result, op_data->balance, op_data->provider, op_data->uid, 
            op_data->agencyid, op_data->gameid, op_data->cycle, op_data->orderid, 
            op_data->optime, op_data->fee, op_data->purchase_time); 

        // 记录 取消操作
        RecordCancelPurchaseReg(
            result, balance, provider, user_id, agency_id, game_id, cycle, optime, fee, 
            purchase_time, order_id, cancel_purchase_orderid);

        //清理缓存
        // log_debug("ClearBetFailed, uid:%u,gameid:%u,matchid:%llu,orderid:%llu", op_data->uid, op_data->gameid, op_data->matchid, op_data->orderid);
        ApiOrderCache::Instance()->ClearMatchRegFailed(cancel_purchase_orderid);
    }
    else
    {
        // 缓存 取消记录
        // log_debug("CacheCancleBet, uid:%u,gameid:%u,matchid:%llu,orderid:%llu,associatedorder:%llu", uid, gameid, matchid, orderid, associatedorder);
        ApiOrderCache::Instance()->CacheCancelMatchReg(cancel_purchase_orderid, CTools::GetUnixTime() + 60);

        // 记录 取消操作
        RecordCancelPurchaseReg(
            result, balance, provider, user_id, agency_id, game_id, cycle, optime, fee, 
            purchase_time, order_id, cancel_purchase_orderid);
    }
}
void FlowService::RecordPurchaseReg(std::int32_t result, std::int64_t balance, const std::string &provider, std::uint32_t user_id, 
    std::uint32_t agency_id, std::uint32_t game_id, std::uint64_t cycle, std::uint64_t order_id, std::uint64_t optime, std::int64_t fee, std::int64_t purchase_time)
{
    if (fee > 0)
    {
        flow::FlowPush flow_push;
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_balance(balance);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->set_uid(user_id);
        flow->mutable_gameinfo()->set_agencyid(agency_id);
        flow->mutable_gameinfo()->set_gameid(game_id);
        flow->mutable_gameinfo()->set_cycle(cycle);
        flow->mutable_gameinfo()->set_orderid(order_id);
        flow->set_optime(optime);
        flow->mutable_op()->set_delt(-fee);
        flow->mutable_op()->set_act(flow::ACT_PURCHASE);
        
        Json::Value ext_data;
        ext_data["purchase_time"] = Json::Int64(purchase_time);
        ext_data["fee"] = Json::Int64(fee);
        std::string ext_string = CTools::ToStr(ext_data);
        flow->set_ext(ext_string);

        log_debug("flow_push:%s;", flow_push.ShortDebugString().c_str());
        Ctx.host->MtSendtoSrv(flow::FLOW_CMD_FLOW_PUSH, SERVER_TYPE_FLOW, &flow_push, user_id);
    }
    else
    {
        log_error("flow_push: purchase_time=%ld, order_id=%lu, fee=%ld, cycle=%lu, user_id=%u, agency_id=%u, game_id=%u;"
            ,purchase_time, order_id, fee, cycle, user_id, agency_id, game_id);
    }
}
void FlowService::RecordCancelPurchaseReg(std::int32_t result, std::int64_t balance, const std::string &provider, std::uint32_t user_id, 
    std::uint32_t agency_id, std::uint32_t game_id, std::uint64_t cycle, std::uint64_t optime, std::int64_t fee, std::int64_t purchase_time, std::uint64_t order_id, std::uint64_t cancel_purchase_orderid) 
{
    if (fee > 0)
    {
        flow::FlowPush flow_push;
        flow::Flow* flow = flow_push.add_flow();
        flow->set_result(result);
        flow->set_uid(user_id);
        flow->mutable_op()->set_act(flow::ACT_CANCEL_PURCHASE);
        flow->mutable_op()->set_delt(fee);
        flow->mutable_gameinfo()->set_provider(provider);
        flow->mutable_gameinfo()->set_agencyid(agency_id);
        flow->mutable_gameinfo()->set_gameid(game_id);
        flow->mutable_gameinfo()->set_cycle(cycle);
        flow->mutable_gameinfo()->set_orderid(order_id);
        flow->mutable_gameinfo()->set_associatedorder(cancel_purchase_orderid);
        flow->set_optime(optime);
        flow->set_balance(balance);

        Json::Value ext_data;
        ext_data["purchase_time"] = Json::Int64(purchase_time);
        ext_data["fee"] = Json::Int64(fee);
        std::string ext_string = CTools::ToStr(ext_data);
        flow->set_ext(ext_string);

        log_debug("flow_push:%s", flow_push.ShortDebugString().c_str());
        Ctx.host->MtSendtoSrv(flow::FLOW_CMD_FLOW_PUSH, SERVER_TYPE_FLOW, &flow_push, user_id);
    }
    else
    {
        log_error("flow_push: purchase_time=%ld, order_id=%lu, cancel_purchase_orderid=%lu, fee=%ld, cycle=%lu, user_id=%u, agency_id=%u, game_id=%u;"
            ,purchase_time, order_id, cancel_purchase_orderid, fee, cycle, user_id, agency_id, game_id);
    }
}